﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FxCopContrib.TestHarness;
using System.Threading;

namespace FxCopContrib.Tests
{
    [TestClass]
    public class RefererenceLocalStructCorrectlyInClosureTests
    {
        [TestMethod]
        public void TriggerOnALocalIntegerWhichIsUsedInACloseAndPassesToAAsyncMethod()
        {
            FxCopTest.ForRule<RefererenceLocalStructCorrectlyInClosure>()
                .OnMethod(
                    @"
                        public void TestMethod()
                        {
                            int i = 0;
                            Thread t = new Thread(() => Console.WriteLine(i));
                            i = 1;
                            t.Start();
                        }
                    ",
                    typeof(Thread).Namespace
                ).WithReferencesTo(typeof(Thread), typeof(Console), typeof(int))
                .WillFind(ProblemPrototype.Default)
                .Conclusive()
                .Verify();
        }

        [TestMethod]
        public void DontTriggerOnALocalIntegerWhichIsPasssedToInACloserAndToAAsyncMethod()
        {
            FxCopTest.ForRule<RefererenceLocalStructCorrectlyInClosure>()
                .OnMethod(
                    @"
                        public void TestMethod()
                        {
                            int i = 0;
                            Thread t = new Thread((c) => Console.WriteLine(c), i);
                            i = 1;
                            t.Start();
                        }
                    ",
                    typeof(Thread).Namespace
                ).WithReferencesTo(typeof(Thread), typeof(Console), typeof(int))
                .WillNotFind(ProblemPrototype.Default)
                .Conclusive()
                .Verify();
        }

        [TestMethod]
        public void TriggerOnALocalWhichIsAlteredAfterBeingUsedInAction()
        {
            FxCopTest.ForRule<RefererenceLocalStructCorrectlyInClosure>()
                .OnMethod(
                    @"
                        public void TestMethod()
                        {
                            int i = 0;
                            Action action = () => Console.WriteLine(i);
                            i = 1;
                            action();
                        }
                    ",
                    typeof(Thread).Namespace
                ).WithReferencesTo(typeof(Action), typeof(Console), typeof(int))
                .WillFind(ProblemPrototype.Default)
                .Conclusive()
                .Verify();
        }

        [TestMethod]
        public void TriggerOnALocalWhichIsUSedInALoopAfterBeingUsedInAction()
        {
            FxCopTest.ForRule<RefererenceLocalStructCorrectlyInClosure>()
                .OnMethod(
                    @"
                        public void TestMethod()
                        {
                            for (int i = 0; i<3; i++)
                            {   
                                Action action = () => Console.WriteLine(i);
                                action.BeginInvoke(null, null);
                            }
                           
                        }
                    ",
                    typeof(Thread).Namespace
                ).WithReferencesTo(typeof(Action), typeof(Console), typeof(int))
                .WillFind(ProblemPrototype.Default)
                .Conclusive()
                .Verify();
        }

        [TestMethod]
        public void DontTriggerOnALocalWhichIsUSedInALoopAfterBeingPassedToAction()
        {
            FxCopTest.ForRule<RefererenceLocalStructCorrectlyInClosure>()
                .OnMethod(
                    @"
                        public void TestMethod()
                        {
                            for (int i = 0; i<3; i++)
                            {   
                                Action<int> action = (c) => Console.WriteLine(c);
                                action.BeginInvoke(i, null, null);
                            }
                           
                        }
                    ",
                    typeof(Thread).Namespace
                ).WithReferencesTo(typeof(Action), typeof(Console), typeof(int))
                .WillNotFind(ProblemPrototype.Default)
                .Conclusive()
                .Verify();
        }

        
    }
}
